package org.taskexecution.taskexecution.task;
import org.taskexecution..taskexecutionaccountcenter.application.scheduledTask.TaskDefinitionService;
import com.cephr.accountcenter.application.scheduledTask.TaskExecutionLogService;
import com.cephr.accountcenter.application.scheduledTask.TaskScheduleService;
import com.cephr.accountcenter.infrastructure.presistent.po.scheduledTask.TaskDefinition;
import com.cephr.accountcenter.infrastructure.presistent.po.scheduledTask.TaskExecutionLog;
import com.cephr.accountcenter.infrastructure.presistent.po.scheduledTask.TaskSchedule;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
/**
 * @author Lydond
 * @description:
 * @create_date: 2025/10/20-16:13
 */


@Service
public class TaskExecutionService {

    @Autowired
    private TaskDispatcher taskDispatcher; // 您已写好的分发器

    // --- 注入您所有的 MP Services ---
    @Autowired
    private TaskScheduleService taskScheduleService;
    @Autowired
    private TaskDefinitionService taskDefinitionService;
    @Autowired
    private TaskExecutionLogService taskExecutionLogService;

    @Autowired
    private ObjectMapper objectMapper;

    // 状态常量 (建议使用枚举)
    private static final int STATUS_COMPLETED = 1;
    private static final int STATUS_FAILED = 2;

    @Async("taskExecutor") // 记得配置线程池
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void executeTask(TaskSchedule task) {

        // 记录开始时间用于计算耗时
        long startNano = System.nanoTime();

        TaskExecutionLog execLog = new TaskExecutionLog();
        execLog.setScheduleId(task.getScheduleId());
        execLog.setTaskDefId(task.getTaskDefId());
        execLog.setStartTime(LocalDateTime.now());

        try {
            // 2. 找到 task_key (使用 MP Service 自带的 getById)
            TaskDefinition def = taskDefinitionService.getById(task.getTaskDefId());
            if (def == null) {
                throw new IllegalArgumentException("未找到任务定义: " + task.getTaskDefId());
            }

            // 3. 【核心调用】
            Object result = taskDispatcher.dispatch(def.getTaskKey(), task.getTaskParams());

            // 4. 执行成功
            execLog.setEndTime(LocalDateTime.now());
            execLog.setIsSuccess(1);
            execLog.setDurationMs((int) ((System.nanoTime() - startNano) / 1_000_000L));
            // 显式设置 createdAt，避免数据库 not null 约束
            execLog.setCreatedAt(LocalDateTime.now());
            if (result != null) {
                execLog.setResultData(objectMapper.writeValueAsString(result));
            }
            try {
                taskExecutionLogService.save(execLog);
            } catch (Exception logEx) {
                // 日志写入失败不应阻断主流程
                System.err.println("任务日志写入失败 scheduleId=" + task.getScheduleId() + ": " + logEx.getMessage());
            }

            // 5. 更新主任务状态 (使用 MP Service 自带的 updateById)
            TaskSchedule updateTask = new TaskSchedule();
            updateTask.setScheduleId(task.getScheduleId());
            updateTask.setStatus(STATUS_COMPLETED);
            updateTask.setLastLogId(execLog.getLogId());
            taskScheduleService.updateById(updateTask);

        } catch (Exception e) {
            // 6. 执行失败
            execLog.setEndTime(LocalDateTime.now());
            execLog.setIsSuccess(0);
            execLog.setDurationMs((int) ((System.nanoTime() - startNano) / 1_000_000L));
            // 尽量保留关键错误信息，避免过长
            String msg = e.getMessage();
            if (msg == null) {
                msg = e.toString();
            }
            // 限制长度，避免超出列宽导致再次插入失败（假定 2000 字符内安全）
            if (msg.length() > 2000) {
                msg = msg.substring(0, 2000);
            }
            execLog.setErrorMessage(msg);
            // 显式设置 createdAt
            execLog.setCreatedAt(LocalDateTime.now());
            try {
                taskExecutionLogService.save(execLog);
            } catch (Exception logEx) {
                System.err.println("任务失败但日志写入再次失败 scheduleId=" + task.getScheduleId() + ": " + logEx.getMessage());
            }

            // 7. 更新主任务状态（无论日志是否写入成功，都要更新状态为失败）
            TaskSchedule updateTask = new TaskSchedule();
            updateTask.setScheduleId(task.getScheduleId());
            updateTask.setStatus(STATUS_FAILED);
            updateTask.setLastLogId(execLog.getLogId());
            taskScheduleService.updateById(updateTask);

            System.err.println("任务执行失败: " + task.getScheduleId() + ", 错误: " + msg);
        }
    }
}